import { useState, useEffect, useCallback, useRef } from "react";
import { Text, View, StatusBar, ActivityIndicator, TouchableOpacity } from "react-native";
import LinearGradient from "react-native-linear-gradient";

import { useDispatch, useSelector } from "react-redux";
import { setEntryNetworkInfo as reduxSetEntryNetworkInfo } from "@/store/slices/index";
import { setPlatformBaseUrl, setProxyUrl, setWebsocketUrl } from "@/store/slices/common";

import styles from "./styles";

import fso from "@/utils/FileOperate/operate";
import sm from "@/utils/ScheduleManage/operate";
import getDeviceInfo from "@/utils/getDeviceInfo";
import { fetchEntryNetworkInfo, getEntryNetworkInfo, setEntryNetworkInfo } from "@/utils/entryNetworkInfoOperate";
import { connect as websocketConnect } from "@/utils/websocket/index";
import { Module } from "@/utils/nativeModules";
import { gotoVideoDisplayPage } from "@/utils";
import { setNativeDate } from "@/utils/date";
import { handleOffLineCmd } from "@/utils/websocket/offLineCmd";

import config from "@/config";
import globalMethods from "@/GlobalMethodProvider";

import Btn from "@/components/Btn";
import CustomIcon from "@/components/CustomIcon";

import { checkDeviceStatus, deviceUpdateVersion, getTime, testNetInfo } from "@/api/home";

import type { StateType } from "./type";
import type { RootState } from "@/store";
import type { HomeProps } from "@/router/routerType";
import type { DeviceType } from "@/typings/businessType";

/** 主菜单 */
const Home = (props: HomeProps) => {
  const [state, _setState] = useState<StateType>({
    isErr: false,
    loadtip: "系统准备中, 请稍等",
    oldAppData: null
  });

  // 通用更新状态单个
  const setState = useCallback((field: keyof typeof state, val: any) => {
    _setState(_state => {
      return { ..._state, [field]: val };
    });
  }, []);

  // 通用更新状态(对象)
  const setObjState = useCallback((obj: Partial<typeof state>) => {
    _setState(_state => {
      return { ..._state, ...obj };
    });
  }, []);

  const isInit = useRef(false);

  const dispatch = useDispatch();

  const { index: reduxIndex } = useSelector((state: RootState) => state);

  /**
   * 处理设备的状态
   */
  const handlDeviceStatus = useCallback(
    async (data?: DeviceType) => {
      if (!data) {
        // 跳转到入网申请页面
        props.navigation.replace("EntryNetwork", { flag: false });
        return;
      }
      // 保存入网信息
      dispatch(reduxSetEntryNetworkInfo(data));
      await setEntryNetworkInfo(data);

      if (reduxIndex.isWebsocketConnect) {
        fso.info("当前已经连接上websocke");
      } else {
        const ws = await websocketConnect();
        if (ws) {
          console.log("============== ws 连接成功 ==============");
        } else {
          fso.warn("没连接上websocket");
        }
      }

      if (data.status === "0") {
        gotoVideoDisplayPage();
      } else if (data.status === "1" || data.status === "2") {
        const statusText = data.status === "1" ? "已暂停" : "已停止";
        const msg = `该设备【${statusText}】`;
        fso.info(msg);
        setObjState({
          isErr: true,
          loadtip: msg
        });
      } else if (data.status === "3") {
        // 跳转到申请完成页面
        props.navigation.replace("EntryNetwork", { flag: true });
      } else if (data.status === "4") {
        // 跳转到申请页面
        props.navigation.replace("EntryNetwork", { flag: false });
      }
    },
    [dispatch, props.navigation, reduxIndex.isWebsocketConnect, setObjState]
  );


  /** 迁移APP数据 */
  const migrationApp = useCallback(async (oldAppData: StateType["oldAppData"]) => {
    if (oldAppData) {
      try {
        const networkInfo = await getEntryNetworkInfo();
        if (networkInfo) {
          initData();
        } else {
          fso.info("设备迁移逻辑, 旧版本的设备编号", oldAppData.devNumber);
          fso.info("旧版本的日志文件: ", config.oldAppInfo.logDir);
          fso.info("旧版本的素材文件: ", config.oldAppInfo.resourceDir);
          fetchEntryNetworkInfo(oldAppData.devNumber);
        }
      } catch (err) {
        console.log("err: ", err);
        fso.error("发生了错误: ", err);
        props.navigation.replace("EntryNetwork", { flag: false });
      }
    } else {
      fso.error("旧版app数据获取失败");
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  /** 处理没网络或者报错 */
  const handleNotNetwork = useCallback(async () => {
    try {
      const res = await getEntryNetworkInfo();
      if (res) {
        fso.info("本地保存的入网信息: ", res);

        dispatch(reduxSetEntryNetworkInfo(res));

        // 已经审核通过的设备
        if (res.status === "0") {
          // 先同步一下本地的数据
          const isFlag = await sm.updateMaterialIsDown();
          if (!isFlag) {
            fso.warn("本地下载的素材和数据库数据未进行同步, 可能会出现重复下载的情况");
          }
          gotoVideoDisplayPage();

          // 已提交入网但是还未审核的设备
        } else {
          props.navigation.replace("EntryNetwork", { flag: true });
        }
      } else {
        const msg = "当前设备没有连接后台, 未找到入网信息, 请联系管理员处理";
        setObjState({ loadtip: msg, isErr: true });
        globalMethods.$warning(msg);
        fso.warn(msg);
      }
    } catch (err) {
      console.log("err: ", err);
      fso.error("发生了错误");
    }
  }, [dispatch, props.navigation, setObjState]);

  /** 初始化网络数据 */
  const initNetworkData = useCallback(async () => {
    try {
      if (isInit.current) {
        console.warn("===== 重复初始化 =====");
        return;
      }
      isInit.current = true;

      await fso.clearBeforeDayFile().catch(err => {
        fso.warn("删除三十天之前的文件失败: ", err);
      });

      const deviceInfo = await getDeviceInfo();
      const appInfo = await Module.getAppInfo().catch(err => {
        fso.warn("本地APP版本信息获取失败: ", err);
      });
      fso.info("设备信息: ", { ...deviceInfo, ...appInfo });

      const msg1 = "测试网络连接";
      fso.info(msg1);
      setObjState({ loadtip: msg1, isErr: false });
      const testNetRes = await testNetInfo().catch(err => {
        console.log("err: ", err);
      });
      if (testNetRes) {
        setObjState({ loadtip: "获取服务器时间" });
        fso.info("获取服务器时间");
        const resTime = await getTime();
        console.log("服务器返回的日期: ", resTime.data);
        // 注意使用模拟器修改时间会导致定时器有问题
        if (!config.IS_DEBUG) {
          await setNativeDate(resTime.data);
        }

        fso.info("发送请求给后台检查当前设备的状态");
        setObjState({ loadtip: "检查设备状态中" });

        const entryNetworkInfo = await getEntryNetworkInfo().catch(err => {
          console.log("err: ", err);
        });

        const uuid = entryNetworkInfo?.uuid || "";
        if (!uuid) {
          // props.navigation.replace("EntryNetwork", { flag: false });

          // 迁移
          if (state.oldAppData) {
            fso.info("本地没有读取到 uuid并且读取到旧旧版本APP数据, 迁移到新版本APP");
            migrationApp(state.oldAppData);
          } else {
            // 跳转到入网申请页面
            props.navigation.replace("EntryNetwork", { flag: false });
          }
          return;
        }

        // 检查设备的状态
        const res = await checkDeviceStatus({ uuid });
        const data: DeviceType | undefined = res.data;
        fso.info("查询的设备状态: -> ", data);

        const isRoot = await Module.isRoot();
        if (!isRoot) {
          globalMethods.$showMessage({
            type: "toast",
            message: "该设备未Root, 部分功能不可用"
          });
        }

        const msg2 = "获取离线指令";
        setObjState({ loadtip: msg2 });
        if (data) {
          const offLineCmdRes = await handleOffLineCmd(data.code);
          if (offLineCmdRes instanceof Error) {
            fso.error("离线指令执行失败: " + offLineCmdRes);
          } else {
            fso.info("离线指令执行完成");
          }

          if (appInfo) {
            fso.info("APP版本数据更新到后台: ", appInfo.versionName);
            // 本地版本号信息更新到后台
            await deviceUpdateVersion({
              deviceCode: data.code,
              version: appInfo.versionName
            }).catch(err => {
              fso.warn("APP版本数据更新失败: ", err);
            });
          }
        } else {
          fso.error("设备未认证通过, 不请求离线指令");
        }
        setObjState({ loadtip: "完成初始化", isErr: true });
        handlDeviceStatus(data);
      } else {
        fso.info("当前没有网络, 检查本地数据");
        setObjState({ loadtip: "离线检查设备状态中", isErr: false });
        handleNotNetwork();
      }
    } catch (err) {
      if (err instanceof Error) {
        setObjState({ loadtip: err.message || "未知错误", isErr: true });
      } else {
        setObjState({ loadtip: `${err}`, isErr: true });
      }
      handleNotNetwork();
      console.log("err: ", err);
    }
  }, [handlDeviceStatus, handleNotNetwork, migrationApp, props.navigation, setObjState, state.oldAppData]);

  /** 读取配置文件 */
  const readConfigFile = useCallback(() => {
    return new Promise<void>(async resolve => {
      try {
        const configFile = `${fso.baseDir}/CONFIG.json`;
        fso.info("读取本地配置文件: ", configFile);
        const exists = await fso.exists(configFile);
        let nativeConfig: typeof config | null = null;
        if (exists) {
          try {
            // 动态读取本地配置文件
            const readText = await fso.readFile(configFile);
            nativeConfig = JSON.parse(readText);
          } catch (err) {
            console.log("err: ", err);
            fso.error("读取本地配置文件数据失败: " + err);
          }
          if (nativeConfig) {
            // 设置到配置对象中
            for (const key in nativeConfig) {
              if (Object.prototype.hasOwnProperty.call(nativeConfig, key)) {
                const value = (nativeConfig as any)[key];

                // 只开放设置个别配置
                if (value) {
                  if (key === "platformBaseUrl") {
                    config.platformBaseUrl = value;
                    dispatch(setPlatformBaseUrl(value));
                  }
                  if (key === "proxyUrl") {
                    config.proxyUrl = value;
                    dispatch(setProxyUrl(value));
                  }
                  if (key === "websocketUrl") {
                    config.websocketUrl = value;
                    dispatch(setWebsocketUrl(value));
                  }
                }
              }
            }
          }
        } else {
          fso.info("本地没有配置文件");
        }

        const oldAppStorageInfo = await readOldAppStorageInfo();
        if (oldAppStorageInfo) {
          fso.info(`旧版APP数据读取成功: `, oldAppStorageInfo);
          state.oldAppData = JSON.parse(oldAppStorageInfo || "{}");
          const exists = await fso.exists(fso.oldAppstorageInfoFilePath);
          if (!exists) {
            fso.info(`旧版APP数据保存到文件: `, fso.oldAppstorageInfoFilePath);
            await fso.writeFile(fso.oldAppstorageInfoFilePath, oldAppStorageInfo);
          }
        } else {
          fso.info("没有读取到旧版APP数据");
        }
      } catch (err) {
        fso.error("读取本地配置文件失败: ", err);
      } finally {
        resolve();
      }
    });
  }, [dispatch, state]);

  /** 读取旧版本APP的数据文件 */
  const readOldAppStorageInfo = async () => {
    return new Promise<null | string>(async resolve => {
      let result = null;
      try {
        const oldAppStorageInfoPath = config.oldAppInfo.storageInfoFilePath;
        await fso.info("读取旧版APP数据, 路径:", oldAppStorageInfoPath);

        // 旧版本路径
        const exist1 = await fso.exists(oldAppStorageInfoPath);
        if (exist1) {
          result = await fso.readFile(oldAppStorageInfoPath);
        } else {
          fso.warn("文件不存在: ", oldAppStorageInfoPath);
        }

        // 新版本路径
        if (!result) {
          await fso.info("读取旧版本APP数据, 路径: ", fso.oldAppstorageInfoFilePath);
          const exists2 = await fso.exists(fso.oldAppstorageInfoFilePath);
          if (exists2) {
            result = await fso.readFile(fso.oldAppstorageInfoFilePath);
          } else {
            fso.warn("文件不存在: ", fso.oldAppstorageInfoFilePath);
          }
        }

        if (!result) {
          await fso.warn("旧版本app数据读取");
        }
      } catch (err) {
        console.log("err: ", err);
      } finally {
        resolve(result);
      }
    });
  };

  /** 初始化数据 */
  const initData = useCallback(() => {
    initNetworkData();
  }, [initNetworkData]);

  /** 初始化 */
  const init = useCallback(async () => {
    try {
      await readConfigFile();
    } catch (err) {
      fso.error("发生了错误: ", err);
    } finally {
      fso.info("配置文件读取完成");
      fso.info("config", config);
      // 迁移
      if (state.oldAppData && state.oldAppData?.devNumber) {
        migrationApp(state.oldAppData);
      } else {
        initData();
      }
    }
  }, [initData, migrationApp, readConfigFile, state.oldAppData]);

  useEffect(() => {
    init();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const DevComp1 = config.IS_DEBUG ? (
    <View style={{ flexDirection: "row", gap: 10 }}>
      <Btn
        text="设备状态"
        type="primary"
        onClick={async () => {
          const entryNetworkInfo = await getEntryNetworkInfo().catch(err => {
            console.log("err: ", err);
          });
          const res = await checkDeviceStatus({
            uuid: entryNetworkInfo?.uuid || ""
          });
          console.log("res.data: ", res.data);
        }}
      />
      <Btn
        type="primary"
        text="跳转入网页面"
        onClick={() => {
          props.navigation.navigate("EntryNetwork", { flag: false });
        }}
      />
      <Btn
        type="primary"
        text="跳转播放页面"
        onClick={() => {
          props.navigation.navigate("VideoDisplay");
        }}
      />
      <Btn
        text="本地保存的入网信息"
        type="primary"
        onClick={() => {
          getEntryNetworkInfo()
            .then(res => {
              console.log("res: ", res);
            })
            .catch(err => {
              console.log("err: ", err);
            });
        }}
      />
    </View>
  ) : null;

  return (
    <LinearGradient colors={["#c2cac7", "#105d5d"]} style={styles.container}>
      <StatusBar hidden />
      <Text style={styles.title}>多媒体信息发布</Text>
      <View style={styles.subTitleContainer}>
        <ActivityIndicator animating={!state.isErr} size={30} color="white" />
        <Text style={styles.subTitle}>{state.loadtip}</Text>
        {state.isErr && (
          <TouchableOpacity
            onPress={() => {
              isInit.current = false;
              init();
            }}
          >
            <CustomIcon name="icon-Sync" size={30} color="white" />
          </TouchableOpacity>
        )}
      </View>

      {DevComp1}
    </LinearGradient>
  );
};

export default Home;
